import junit.framework.TestCase;

import java.util.HashMap;
import java.util.Iterator;

import de.unibi.comet.ac.SuffixStructure;
import de.unibi.comet.ac.SuffixStructureNode;
import de.unibi.comet.ac.EnhancedSuffixArray;

public class EnhancedSuffixArrayTest extends TestCase {
	private static HashMap<String,SuffixStructureNode> iterate(Iterator<SuffixStructureNode> iter) {
		HashMap<String,SuffixStructureNode> map = new HashMap<String,SuffixStructureNode>();
		while (iter.hasNext()) {
			SuffixStructureNode child = iter.next();
			String s = child.getText();
			map.put(s, child);
		}		
		return map;
	}
	
	private static void assertSingleton(SuffixStructureNode node) {
		assertFalse(node.childrenIterator().hasNext());
		assertFalse(node.isRoot());
	}

	private static void assertNode(SuffixStructureNode parent, HashMap<String,SuffixStructureNode> map, String name, boolean isSuffix, String edgeText) {
		assertTrue(map.containsKey(name));
		SuffixStructureNode node = map.get(name);
		assertEquals(isSuffix, node.isSuffix());
		assertEquals(parent, node.getParent());
		assertEquals(edgeText, node.getEdgeText());
		assertFalse(node.isRoot());
		char c = node.getText().charAt(parent.getText().length());
		char c_diff = (c=='a'?'b':'a');
		assertEquals(node, parent.getChildByChar(c));
		assertFalse(node.equals(parent.getChildByChar(c_diff)));
	}
	
	private static void assertMississippi(SuffixStructure sufStruct) {
		HashMap<String,SuffixStructureNode> map1 = null;
		HashMap<String,SuffixStructureNode> map2 = null;
		HashMap<String,SuffixStructureNode> map3 = null;

		SuffixStructureNode parent = sufStruct.getRoot();
		assertNull(parent.getParent());
		assertTrue(parent.isRoot());
		map1=iterate(parent.childrenIterator());
		
		// --
		assertEquals(4, map1.size());
		assertNode(parent, map1, "i", true, "i");
		assertNode(parent, map1, "mississippi", true, "mississippi");
		assertNode(parent, map1, "p", false, "p");
		assertNode(parent, map1, "s", false, "s");
		assertSingleton(map1.get("mississippi"));
		
		// ----
		parent=map1.get("i");
		map2=iterate(parent.childrenIterator());
		assertEquals(2, map2.size());
		assertNode(parent, map2, "issi", false, "ssi");
		assertNode(parent, map2, "ippi", true, "ppi");
		assertSingleton(map2.get("ippi"));
		// -----
		parent=map2.get("issi");
		map3=iterate(parent.childrenIterator());
		assertEquals(2, map3.size());
		assertNode(parent, map3, "ississippi", true, "ssippi");
		assertNode(parent, map3, "issippi", true, "ppi");
		assertSingleton(map3.get("ississippi"));
		assertSingleton(map3.get("issippi"));
		
		// ----
		parent=map1.get("p");
		map2=iterate(parent.childrenIterator());
		assertEquals(2, map2.size());
		assertNode(parent, map2, "pi", true, "i");
		assertNode(parent, map2, "ppi", true, "pi");
		assertSingleton(map2.get("pi"));
		assertSingleton(map2.get("ppi"));
		// ----
		parent=map1.get("s");
		map2=iterate(parent.childrenIterator());
		assertEquals(2, map2.size());
		assertNode(parent, map2, "si", false, "i");
		assertNode(parent, map2, "ssi", false, "si");
		// -----
		parent=map2.get("si");
		map3=iterate(parent.childrenIterator());
		assertEquals(2, map3.size());
		assertNode(parent, map3, "sissippi", true, "ssippi");
		assertNode(parent, map3, "sippi", true, "ppi");
		assertSingleton(map3.get("sissippi"));
		assertSingleton(map3.get("sippi"));
		// -----
		parent=map2.get("ssi");
		map3=iterate(parent.childrenIterator());
		assertEquals(2, map3.size());
		assertNode(parent, map3, "ssissippi", true, "ssippi");
		assertNode(parent, map3, "ssippi", true, "ppi");
		assertSingleton(map3.get("ssissippi"));
		assertSingleton(map3.get("ssippi"));
	}
	
	public void testSingleString() {
		SuffixStructure sufStruct = new EnhancedSuffixArray();
		sufStruct.build("mississippi");
		assertMississippi(sufStruct);
		sufStruct.build("mississippi$");
		assertMississippi(sufStruct);
		sufStruct.build("$mississippi");
		assertMississippi(sufStruct);
		sufStruct.build("$mississippi$");
		assertMississippi(sufStruct);
	}
	
	public void testMultipleStrings() {
		SuffixStructure sufStruct = new EnhancedSuffixArray();
		sufStruct.build("$bac$ac$abcd$aba$");
		
		HashMap<String,SuffixStructureNode> map1 = null;
		HashMap<String,SuffixStructureNode> map2 = null;
		HashMap<String,SuffixStructureNode> map3 = null;

		SuffixStructureNode parent = sufStruct.getRoot(); 
		assertNull(parent.getParent());
		assertTrue(parent.isRoot());
		map1=iterate(parent.childrenIterator());
		
		// --
		assertEquals(4, map1.size());
		assertNode(parent, map1, "a", true, "a");
		assertNode(parent, map1, "b", false, "b");
		assertNode(parent, map1, "c", true, "c");
		assertNode(parent, map1, "d", true, "d");
		assertSingleton(map1.get("d"));
		
		// ----
		parent=map1.get("a");
		map2=iterate(parent.childrenIterator());
		assertEquals(2, map2.size());
		assertNode(parent, map2, "ac", true, "c");
		assertNode(parent, map2, "ab", false, "b");
		assertSingleton(map2.get("ac"));
		
		// -----
		parent=map2.get("ab");
		map3=iterate(parent.childrenIterator());
		assertEquals(2, map3.size());
		assertNode(parent, map3, "aba", true, "a");
		assertNode(parent, map3, "abcd", true, "cd");
		assertSingleton(map3.get("aba"));
		assertSingleton(map3.get("abcd"));
		
		// ----
		parent=map1.get("b");
		map2=iterate(parent.childrenIterator());
		assertEquals(2, map2.size());
		assertNode(parent, map2, "ba", true, "a");
		assertNode(parent, map2, "bcd", true, "cd");
		assertSingleton(map2.get("bcd"));

		// -----
		parent=map2.get("ba");
		map3=iterate(parent.childrenIterator());
		assertEquals(1, map3.size());
		assertNode(parent, map3, "bac", true, "c");
		assertSingleton(map3.get("bac"));

		parent=map1.get("c");
		map2=iterate(parent.childrenIterator());
		assertEquals(1, map2.size());
		assertNode(parent, map2, "cd", true, "d");
		assertSingleton(map2.get("cd"));
	}
}
